﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
using YasharEl.Infrastructure.Diagnostics.Logging;
using YasharEl.Infrastructure.ResourcesManagement.Managers;

namespace YasharEl.Infrastructure.ResourcesManagement.Providers
{
    /// <summary>
    /// Base class for resource providers. Contains implementations of common policies
    /// and utilities usable by all resource providers.
    /// </summary>
    /// 
    // TODO : Rename to AbstractResourceProvider or BaseResourceProvider
    public abstract class ResourceProvider : IResourceProvider
    {
        #region Fields

        private string currentResourceManager;
        private ExtendedComponentResourceManager resourceManager;
        private string resourceBaseName;
        private readonly ILogger<ResourceProvider> logger;

        #endregion

        #region Properties

        protected ILogger<ResourceProvider> Logger
        {
            get { return logger; }
        }

        #endregion

        #region Properties

        /// <summary>
        /// <para>Gets the current name of the <see cref="EntLibContrib.Resource.ResourceManager"/> using this provider instance.</para>
        /// </summary>
        /// <value>
        /// <para>The name of the <see cref="EntLibContrib.Resource.ResourceManager"/>.</para>
        /// </value>
        public string CurrentResourceManager
        {
            get { return currentResourceManager; }
        }

        /// <summary>
        /// <para>Gets the current <see cref="ExtendedComponentResourceManager" /> instance.</para>
        /// </summary>
        /// <value>
        /// <para>The internal <see cref="ExtendedComponentResourceManager"/> instance.</para>
        /// </value>
        protected ExtendedComponentResourceManager ResourceManager
        {
            get { return resourceManager; }
            set { resourceManager = value; }
        }

        /// <summary>
        /// Gets or sets the name of the resource base.
        /// </summary>
        /// <value>The name of the resource base.</value>
        protected string ResourceBaseName
        {
            get { return resourceBaseName; }
            set { resourceBaseName = value; }
        }

        #endregion

        #region Construction

        /// <summary>
        /// Initializes a new instance of the <see cref="ResourceProvider"/> class.
        /// </summary>
        /// <param name="resourceBaseName">Name of the resource base.</param>
        protected ResourceProvider(string resourceBaseName, ILogger<ResourceProvider> logger)
            : this(resourceBaseName, false, logger)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ResourceProvider"/> class.
        /// </summary>
        /// <param name="resourceBaseName">Name of the resource base.</param>
        /// <param name="isInternal">if set to <c>true</c> then the provider is for internal resources.</param>
        protected ResourceProvider(string resourceBaseName, bool isInternal, ILogger<ResourceProvider> logger)
        {
            Contract.Requires<ArgumentNullException>(logger != null, "logger could not be null.");

            this.logger = logger;
            // if the provider is for internal resources then validation must be bypassed,
            // otherwise we end up in circles.
            if (!isInternal)
                ValidateParameter(resourceBaseName);

            this.resourceBaseName = resourceBaseName;
        }
        #endregion

        #region Public Methods

        /// <summary>
        /// Create a Resource Manager to manage the resource for a given resource provider
        /// </summary>
        /// <returns>
        /// A <see cref="ExtendedComponentResourceManager"/> instance
        /// </returns>
        /// <remarks>This method makes a <see cref="ExtendedComponentResourceManager"/> instance publicly available
        /// without the caller needing to know where the resources are provided from</remarks>
        public abstract ExtendedComponentResourceManager CreateResourceManager();

        #endregion

        #region Private Methods

        /// <summary>
        /// Validates the resource base name parameter.
        /// </summary>
        /// <param name="resourceBaseName">Name of the resource base.</param>
        private void ValidateParameter(string resourceBaseName)
        {
            Contract.Requires<ArgumentNullException>(!string.IsNullOrEmpty(resourceBaseName), "resourceBaseName could not be null or empty.");

            // store the base name
            this.resourceBaseName = resourceBaseName;
        }

        #endregion
    }
}
